package com.gitee.wsl.api


fun interface Matcher<T : Key<T>> {
    
    fun isMatch(key: T): Boolean

    fun and( rightOperand: Matcher<T>): AndMatcher<T> {
        return and(this, rightOperand)
    }

    fun or( rightOperand: Matcher<T>): OrMatcher<T> {
        return or(this, rightOperand)
    }

    fun not(): NotMatcher<T> {
        return not(this)
    }

    companion object {

        /**
         * Create an AndMatcher that depends upon the result of both of the given
         * matchers.
         */
        
        fun <U : Key<U>> and(
            leftOperand: Matcher<U>,
            rightOperand: Matcher<U>,
        ): AndMatcher<U> {
            return AndMatcher(leftOperand, rightOperand)
        }

        /**
         * Create an OrMatcher that depends upon the result of at least one of the
         * given matchers.
         */
        
        fun <U : Key<U>> or(
            leftOperand: Matcher<U>,
            rightOperand: Matcher<U>,
        ): OrMatcher<U> {
            return OrMatcher(leftOperand, rightOperand)
        }

        /**
         * Create a NotMatcher that reverses the result of the given matcher.
         */
        
        fun <U : Key<U>> not( operand: Matcher<U>): NotMatcher<U> {
            return NotMatcher(operand)
        }
    }
}

/**
 * Matches using an AND operator on two Matcher operands.
 *
 * @author jhouse
 */
class AndMatcher<T : Key<T>>(
    val leftOperand: Matcher<T>,
    val rightOperand: Matcher<T>,
) : Matcher<T> {
    override fun isMatch(key: T): Boolean {
        return leftOperand.isMatch(key) && rightOperand.isMatch(key)
    }
}

/**
 * Matches on the complete key being equal (both name and group).
 *
 * @author jhouse
 */
class KeyMatcher<T : Key<T>>(val compareToValue: T) : Matcher<T> {

    override fun isMatch(key: T): Boolean {
        return compareToValue == key
    }

    companion object {
        /**
         * Create a KeyMatcher that matches Keys that equal the given key.
         */
        fun <U : Key<U>> keyEquals(compareTo: U): KeyMatcher<U> {
            return KeyMatcher(compareTo)
        }
    }
}

/**
 * An abstract base class for some types of matchers.
 *
 * @author jhouse
 */
abstract class StringMatcher<T : Key<T>>(
    val compareToValue: String,
    val compareWithOperator: EStringOperatorName,
) : Matcher<T> {
    enum class EStringOperatorName {
        EQUALS {
            override fun evaluate( value: String,  sCompareTo: String): Boolean {
                return value == sCompareTo
            }
        },

        STARTS_WITH {
            override fun evaluate( value: String,  sCompareTo: String): Boolean {
                return value.startsWith(sCompareTo)
            }
        },

        ENDS_WITH {
            override fun evaluate( value: String,  sCompareTo: String): Boolean {
                return value.endsWith(sCompareTo)
            }
        },

        CONTAINS {
            override fun evaluate( value: String,  sCompareTo: String): Boolean {
                return value.contains(sCompareTo)
            }
        },

        ANYTHING {
            override fun evaluate( value: String,  sCompareTo: String): Boolean {
                return true
            }
        };

        abstract fun evaluate( value: String,  sCompareTo: String): Boolean
    }

    protected abstract fun getValue(key: T): String

    override fun isMatch(key: T): Boolean {
        return compareWithOperator.evaluate(getValue(key), compareToValue)
    }
}

/**
 * Matches using an OR operator on two Matcher operands.
 *
 * @author jhouse
 */
class OrMatcher<T : Key<T>>(
    val leftOperand: Matcher<T>,
    val rightOperand: Matcher<T>,
) : Matcher<T> {
    override fun isMatch(key: T): Boolean {
        return leftOperand.isMatch(key) || rightOperand.isMatch(key)
    }
}

/**
 * Matches using an NOT operator on another Matcher.
 *
 * @author jhouse
 */
class NotMatcher<T : Key<T>>( val operand: Matcher<T>) : Matcher<T> {
    override fun isMatch(key: T): Boolean {
        return !operand.isMatch(key)
    }
}

class EverythingMatcher <T : Key<T>>() : Matcher<T> {
    override fun isMatch(key: T): Boolean {
        return true
    }
}
